﻿using System;
using System.Collections;
using System.Threading.Tasks;
using NBitcoin;
using Nethereum.Hex.HexConvertors.Extensions;
using Nethereum.Hex.HexTypes;
using Nethereum.RPC.Eth.DTOs;
using Nethereum.Web3.Accounts;
using Nethereum.Signer;
using UnityEngine;
using WalletConnectSharp.Core.Models.Ethereum;
using WalletConnectSharp.Unity;
using ZyGame;

public sealed class ETH
{
    public static string[] CreateMnemonic()
    {
        return new Mnemonic(Wordlist.English, WordCount.Twelve).Words;
    }

    public static (string, string) CreateAccount(string mnemon)
    {
        Mnemonic mnemonic = new Mnemonic(mnemon);
        var ecKey = new EthECKey(mnemonic.DeriveExtKey().PrivateKey.ToHex());
        string PRIVATE_KEY = ecKey.GetPrivateKeyAsBytes().ToHex();
        string PUBLIC_KEY = ecKey.GetPublicAddress();
        return (PRIVATE_KEY, PUBLIC_KEY);
    }

    public static async Task<string> Personal(string privateKey, string token)
    {
        var account = new Account(privateKey);
        return await account.AccountSigningService.PersonalSign.SendRequestAsync(new HexUTF8String(token), 97);
    }

    public static void SignTransactionAsync(string data, string addressTo, string addressFrom, string gas, Action<string> createTransactionback, Action<string> callback)
    {
        TransactionData transactionData = new TransactionData()
        {
            chainId = WalletConnect.Instance.chainId,
            data = data,
            from = addressFrom,
            to = addressTo,
            gas = gas
        };
        string authCode = String.Empty;

        IEnumerator Coroutine()
        {
            createTransactionback?.Invoke(WalletConnect.ActiveSession.URI);
            if (WalletConnect.ActiveSession.Accounts == null || WalletConnect.ActiveSession.Accounts.Length == 0)
            {
                yield return new WaitUntil(CheckWalletReadyCompletion);
                WalletConnect.Instance.OpenDeepLink();
            }

            yield return new WaitUntil(CheckWalletConnectSuccess);
            if (WalletConnect.ActiveSession.Accounts[0] != addressFrom)
            {
                Client.Window.MsgBox("Authorization wallet and account binding wallet are inconsistent");
                callback?.Invoke(String.Empty);
                yield break;
            }

            SendTransaction();
            yield return new WaitUntil(CheckAuthorizationSuccess);
            callback(authCode);
        }

        Client.Tools.StartCoroutine(Coroutine());

        bool CheckAuthorizationSuccess()
        {
            return authCode.IsNullOrEmpty() is false;
        }

        async void SendTransaction()
        {
            authCode = await WalletConnectActions.instance.SendTransaction(transactionData);
        }

        bool CheckWalletReadyCompletion()
        {
            return WalletConnect.ActiveSession.ReadyForUserPrompt;
        }

        bool CheckWalletConnectSuccess()
        {
            return WalletConnect.ActiveSession.Accounts != null && WalletConnect.ActiveSession.Accounts.Length > 0;
        }
    }
}